package com.blank.gps;

import static com.blank.gps.SatelliteUtils.isForceFullGnssMeasurementsSupported;

import android.annotation.SuppressLint;
import android.content.Context;
import android.location.GnssMeasurementRequest;
import android.location.GnssMeasurementsEvent;
import android.location.GnssStatus;
import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Author: blank
 * Date: 2022/3/14 11:08
 * Description: 位置信息
 */
public class MyLocationObserver implements LifecycleObserver {

    private static final String TAG = "blank_gps";
    // Listeners for Fragments
    public static List<GpsListener> mGpsTestListeners = new ArrayList<>();
    private static LocationManager mLocationManager = null;
    private final Context mContext;
    private MyLocationListener mLocationListener = null;
    private boolean mStarted;
    private GnssStatus.Callback mGnssStatusListener;
    private GnssStatus mGnssStatus;
    private GnssMeasurementsEvent.Callback mGnssMeasurementsListener;
    private LocationListener locationListener;
    private GpsStatus mLegacyStatus;
    private Location mLastLocation;
    private GpsStatus.Listener mLegacyStatusListener;

    public MyLocationObserver(Context context) {
        mContext = context;
    }

    public static void addListener(GpsListener listener) {
        mGpsTestListeners.add(listener);
    }

    public static LocationManager getLocationManager() {
        return mLocationManager;
    }

    @SuppressLint("MissingPermission")
    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    private void startGetLocation() {
        Log.d(TAG, "startGetLocation");
        mLocationListener = new MyLocationListener();
        mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
        if (!mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            Log.e(TAG, "Unable to get GPS_PROVIDER");
            Toast.makeText(mContext.getApplicationContext(), "请检查系统设置或者设备不支持GNSS/GPS。", Toast.LENGTH_SHORT).show();
        }
        mStarted = true;
        locationListener = new LocationListener() {
            @Override
            public void onLocationChanged(Location location) {
                // 更新当前设备的位置信息
//                Log.d(TAG, "onLocationChanged: " + l.toString());
                mLastLocation = location;
                for (GpsListener listener : mGpsTestListeners) {
                    listener.onLocationChanged(location);
                }
            }

            @Override
            public void onStatusChanged(String provider, int status, Bundle extras) {
//                Log.d(TAG, "onStatusChanged: " + provider + " **" + status + " **" + extras.toString());
                try {
                    for (GpsListener listener : mGpsTestListeners) {
                        listener.onStatusChanged(provider, status, extras);
                    }
                } catch (AbstractMethodError error) {
                    error.printStackTrace();
                }

            }

            @Override
            public void onProviderEnabled(String provider) {
                Log.d(TAG, "onProviderEnabled: " + provider);
                try {
                    for (GpsListener listener : mGpsTestListeners) {
                        listener.onProviderEnabled(provider);
                    }
                } catch (AbstractMethodError error) {
                    error.printStackTrace();
                }

            }

            @Override
            public void onProviderDisabled(String provider) {
                Log.d(TAG, "onProviderDisabled: " + provider);

                try {
                    for (GpsListener listener : mGpsTestListeners) {
                        listener.onProviderDisabled(provider);
                    }
                } catch (AbstractMethodError error) {
                    error.printStackTrace();
                }

            }
        };

        if (mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            //每隔10米更新位置
            mLocationManager.requestLocationUpdates(
                    LocationManager.GPS_PROVIDER,
                    1000L,
                    0f,
                    locationListener
            );
        }
        if (mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
            //每隔10米更新位置
            mLocationManager.requestLocationUpdates(
                    LocationManager.NETWORK_PROVIDER,
                    1000L,
                    0f,
                    locationListener
            );
        }


        for (GpsListener listener : mGpsTestListeners) {
            listener.gpsStart();
        }
        addGnssMeasurementsListener();
        if (SatelliteUtils.isGnssStatusListenerSupported()) {
            addGnssStatusListener();
        } else {
            //gpsstatus
            addLegacyStatusListener();
        }
    }

    @SuppressLint("MissingPermission")
    private void addLegacyStatusListener() {
        mLegacyStatusListener = event -> {
            mLegacyStatus = mLocationManager.getGpsStatus(mLegacyStatus);
            switch (event) {
                case GpsStatus.GPS_EVENT_STARTED:
                    break;
                case GpsStatus.GPS_EVENT_STOPPED:
                    //定位结束
                    break;
                case GpsStatus.GPS_EVENT_FIRST_FIX:
                    //第一次定位
                    for (GpsListener listener : mGpsTestListeners) {
                        listener.onGnssFixAcquired();
                    }
                    break;
                case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
                    //卫星状态改变
                    // 获取当前状态
                    // 包括 卫星的高度角、方位角、信噪比、和伪随机号（及卫星编号）
                    /*
                     * satellite.getElevation(); //卫星仰角
                     * satellite.getAzimuth();   //卫星方位角
                     * satellite.getSnr();       //信噪比
                     * satellite.getPrn();       //伪随机数，可以认为他就是卫星的编号
                     * satellite.hasAlmanac();   //卫星历书
                     * satellite.hasEphemeris();
                     * satellite.usedInFix();
                     */
                    checkHaveFix();
                    break;
            }
            for (GpsListener listener : mGpsTestListeners) {
                listener.onGpsStatusChanged(event, mLegacyStatus);
            }
        };
        mLocationManager.addGpsStatusListener(mLegacyStatusListener);
    }

    private void checkHaveFix() {
        if (mLastLocation != null) {
            if ((SystemClock.elapsedRealtimeNanos() - mLastLocation.getElapsedRealtimeNanos()) >
                    TimeUnit.MILLISECONDS.toNanos(1L)) {
                // We lost the GNSS fix for two requested update intervals - show the progress bar while we try to obtain another one
                for (GpsListener listener : mGpsTestListeners) {
                    listener.onGnssFixLost();
                }
            } else {
                // We have a GNSS fix - hide the progress bar
                for (GpsListener listener : mGpsTestListeners) {
                    listener.onGnssFixAcquired();
                }
            }
        }
    }

    @SuppressLint({"NewApi", "MissingPermission"})
    private void addGnssStatusListener() {
        mGnssStatusListener = new GnssStatus.Callback() {
            @Override
            public void onStarted() {
                for (GpsListener listener : mGpsTestListeners) {
                    listener.onGnssStarted();
                }
            }

            @Override
            public void onStopped() {
                for (GpsListener listener : mGpsTestListeners) {
                    listener.onGnssStopped();
                }
            }

            @Override
            public void onFirstFix(int ttffMillis) {
                for (GpsListener listener : mGpsTestListeners) {
                    listener.onGnssFirstFix(ttffMillis);
                    listener.onGnssFixAcquired();
                }
            }

            @Override
            public void onSatelliteStatusChanged(GnssStatus status) {
                mGnssStatus = status;
                checkHaveFix();
                for (GpsListener listener : mGpsTestListeners) {
                    listener.onSatelliteStatusChanged(mGnssStatus);
                }
            }
        };
        mLocationManager.registerGnssStatusCallback(mGnssStatusListener);
    }

    @SuppressLint({"NewApi", "MissingPermission"})
    private void addGnssMeasurementsListener() {
        mGnssMeasurementsListener = new GnssMeasurementsEvent.Callback() {
            @Override
            public void onGnssMeasurementsReceived(GnssMeasurementsEvent event) {
                for (GpsListener listener : mGpsTestListeners) {
                    listener.onGnssMeasurementsReceived(event);
                }
            }

            @Override
            public void onStatusChanged(int status) {
                // These status messages are deprecated on Android S and higher and should not be used
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                    return;
                }
            }
        };
        if (isForceFullGnssMeasurementsSupported()) {
            // Request "force full GNSS measurements" explicitly (on <= Android R this is a manual developer setting)
            GnssMeasurementRequest request = new GnssMeasurementRequest.Builder()
                    .setFullTracking(true)
                    .build();
            mLocationManager.registerGnssMeasurementsCallback(request, mContext.getApplicationContext().getMainExecutor(), mGnssMeasurementsListener);
        } else {
            mLocationManager.registerGnssMeasurementsCallback(mGnssMeasurementsListener);
        }

    }

    @SuppressLint("MissingPermission")
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    private void stopGetLocation() {
        Log.d(TAG, "stopGetLocation");
        mLocationManager.removeUpdates(locationListener);
        for (GpsListener listener : mGpsTestListeners) {
            listener.gpsStop();
        }
    }

    public static class MyLocationListener implements LocationListener {

        private static OnLocationChange mLocationChangeCall = null;

        public static void setLocationChangeCall(OnLocationChange locationChangeCall) {
            mLocationChangeCall = locationChangeCall;
        }

        @Override
        public void onLocationChanged(@NonNull Location location) {
            setLocationData(mLocationChangeCall, location.getLongitude() + "", location.getLatitude() + "");
        }

        private void setLocationData(OnLocationChange locationChangeCall, String longitude, String latitude) {
            locationChangeCall.locationChange(longitude, latitude);
        }

    }
}
